'''
Created on 15/02/2011

@author: Vinicius

Support Vector machines
'''

import numpy as np
from numpy import matrix, array, power, dot
import cvxopt
import cvxopt.solvers
cvxopt.solvers.options['show_progress'] = False

#Computa o kernel polinomial
##TODO testar o kernel de base radial
def kernel_polinomial(i, p):
    xi = x[i]
    k = (1 + dot(xi , x.T)) ** p
    for j in range(len(k)):
        K[i][j] = k[j]
    return k

#Retorna os multiplicadores de lagrange
def lagrange_multipliers():   
    y = np.outer(d, d)
    P = cvxopt.matrix(y * K)
    q = cvxopt.matrix(np.ones(n[0]) * -1)
    A = cvxopt.matrix(d, (1, n[0]), tc='d')
    b = cvxopt.matrix(0.0)
    G = cvxopt.matrix(np.diag(np.ones(n[0]) * -1))
    h = cvxopt.matrix(np.zeros(n[0]))
 
    solution = cvxopt.solvers.qp(P, q, G, h, A, b)
    a = np.ravel(solution['x']) 
    return a

#Computa o vetor de pesos otimos
def optimal_weights():
    w = np.zeros(n[0])
    for i in range(len(x)):
        ml = a[i]
        y = d[i]
        xi = K[i]
        temp = ml * y * xi
        for j in range(len(w)):
            w[j] += round(temp[j], 4)
    return w

#Realiza a predicao das classes
def predict():
    return np.sign(optimal_weights())

def execute(input, desiredOutput):
    global x, d, a, n, K
    x = input
    d = desiredOutput  
    n = x.shape
    K = np.zeros((n[0], n[0]))  
    for j in range(len(x)):
        kernel_polinomial(j, 2)
    a = lagrange_multipliers()
    return predict()
    
